package com.example.test.async;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.example.test.util.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService{
    private RestTemplate restTemplate;
    private String token;
    private CloseableHttpClient client;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @PostConstruct
    public void init() {
        restTemplate = new RestTemplateBuilder().build();
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            /**
             * 设置RestTemplate自带的异常处理器不做异常处理
             **/
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
            }
        });

        client = HttpClients.createDefault();
        token = login();
    }

    private String login() {
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        param.add("username","wangbo");
        param.add("password", Base64.getEncoder().encode("123456".getBytes(StandardCharsets.UTF_8)));

        String url = String.format("http://%s:%s/service/api/%s", "192.168.88.245", "8080", "user/login");
        String result = restTemplate.postForObject(url, param, String.class);
        return result;
    }

    @Override
    public List<String> recognize(String dirPath, int num, int times) throws ExecutionException, InterruptedException {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();
        Queue<File> queue = new ConcurrentLinkedQueue<>();
        List<String> results = new ArrayList<>(num * times);
        List<Future<String>> futures = new ArrayList<>(num * times);

        // 准备队列
        for (int i = 0; i < times; i++) {
            for (int j = 0; j < num; j++) {
                queue.add(files[j]);
            }
        }

        // 异步线程池执行
        for (int i = 0; i < num * times; i++) {
            Future<String> future = threadPoolTaskExecutor.submit(() -> {
                File file = queue.poll();
                String result = search(file);
//                String result = search2(file);
                log.info("识别结果：{}", result);
                return result;
            });
            futures.add(future);
        }

        // 返回结果
        for (int i = 0; i < num * times; i++) {
            String result = futures.get(i).get();
            results.add(result);
        }

        return results;
    }


    /**
     * 识别 restTemplate
     **/
    private String search(File file) {
        long begin = System.currentTimeMillis();

        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", token);
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        String url = String.format("http://%s:%s/service/api/%s", "192.168.88.245", "8080", "search");
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        String str = Base64.getEncoder().encodeToString(FileUtil.readBytes(file));
        param.add("image-data", "data:image/jpeg;base64," + str);
        param.add("calibrated-threshold", 50);
        param.add("tops", 1);

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(param, headers);


        long middle = System.currentTimeMillis();
        log.info("初始化时间：{}", middle - begin);
        String result = restTemplate.postForObject(url, httpEntity, String.class);
        long end = System.currentTimeMillis();
        log.info("调用搜索接口时间：{}", end - middle);


        return result;
    }

    /**
     * 识别 httpClient
     **/
    private String search2(File file) throws IOException {
        long begin = System.currentTimeMillis();

        // 配置连接
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)//一、连接超时：connectionTimeout-->指的是连接一个url的连接等待时间
                .setSocketTimeout(5000)// 二、读取数据超时：SocketTimeout-->指的是连接上一个url，获取response的返回等待时间
                .setConnectionRequestTimeout(5000)
                .build();

        // 创建httpEntity
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        String str = Base64.getEncoder().encodeToString(FileUtil.readBytes(file));
        params.add(new BasicNameValuePair("image-data", "data:image/jpeg;base64," + str));
        params.add(new BasicNameValuePair("calibrated-threshold", "50"));
        params.add(new BasicNameValuePair("tops", "1"));
        org.apache.http.HttpEntity httpEntity = new UrlEncodedFormEntity(params, "utf-8");

        // 创建request
        String url = String.format("http://%s:%s/service/api/%s", "192.168.88.245", "8080", "search");
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Authorization", token);
        httpPost.setConfig(requestConfig);
        httpPost.setEntity(httpEntity);

        // 发送请求
        long middle = System.currentTimeMillis();
        log.info("初始化时间：{}", middle - begin);
        CloseableHttpResponse response = client.execute(httpPost);
        long end = System.currentTimeMillis();
        log.info("调用搜索接口时间：{}", end - middle);

        // 解析响应结果
        String result = EntityUtils.toString(response.getEntity(), "utf-8");
        return result;
    }
}
